//
//  HomeViewModel.swift
//  HomeViewModel
//
//  Created by Ben on 2021/8/13.
//
import Foundation
import UIKit
import SwiftUI
import Combine

let HOME_RECOMMEND_CLASSES_TAB_ANIMATION_ID = "HOME_RECOMMEND_CLASSES_TAB_ANIMATION_ID"

@MainActor
class HomeViewModel: ObservableObject, IdlefishRequest {
    
    @Published var recommendGoodsListScrollEnable: Bool = false
    
    @Published var showSearchScope: Bool = false
    @Published var currSearchScope: SearchScope = .all
    
    // 当前城市的分类列表
    @Published var currLocationCategoryList: [HomeRecommendGoodsCategoryModel] = []
    var currLocationCategoryCurrTab: HomeRecommendGoodsCategoryModel?
    @Published var currLocationCategoryCurrTabIndex: Int = 0

    // 用来控制显示制定频道
    @Published var showSetChannel: Bool = false
    
    // 我的频道
    @Published var myChannelList: [HomeRecommendGoodsCategoryModel] = []
    
    // 所有顶级分类
    @Published var superCategoryList: [HomeRecommendGoodsCategoryModel] = []
    
    // 当前选中的顶级分类
    @Published var selectedSuperCategory: HomeRecommendGoodsCategoryModel? = nil
    
    // 当前选中的顶级分类下的所有子分类
    @Published var selectedChildCategoryList: [HomeRecommendGoodsCategoryModel] = []
    
       
    // 关注列表的商品动态
    @Published var attentionUserMoments: [GoodsCardModel] = []
    
    // 关注的人列表
    @Published var attentionUserList: [UserModel] = []
    
    // 首页当前显示中的标签
    @Published var currNavTab: HomeNavTab = .recommend
   
    var homeRecommendCurrTab: HomeRecommendGoodsCategoryModel!
    // 这里是选中的分类在分类数组中对应的index
    @Published var homeRecommendCurrTabIndex: Int = 0
    
    // 推荐界面获取分类下商品卡片列表的通知
    private var getRecommendGoodsCardListWithSelectedCategoryPublisher: AnyPublisher<Bool, Never> {
        
        // 合并myChannelList与homeRecommendCurrTabIndex最近一次发出的通知，生成一个新的通知，
        // 该通知的含义是当myChannelList有值，并且homeRecommendCurrTabIndex发生改变的时候触发
        Publishers.CombineLatest($myChannelList, $homeRecommendCurrTabIndex)
            .debounce(for: 0.2, scheduler: RunLoop.main)
            .map { myChannelList, _ in
                return myChannelList.count > 0
            }
            .eraseToAnyPublisher()
    }
    
    // 存储分类及对应的商品列表
    @Published var channelGoodsCardList: [String: [GoodsCardModel]] = [:]
    
    private var cancellable: Set<AnyCancellable> = []

    
    init() {
        
        if IdleFishUserDefaultsManager.shared.myChannels.count > 0 {
            myChannelList = IdleFishUserDefaultsManager.shared.myChannels
        }
        
        // 当关注的人列表数据发生变化的时候，就需要获取该页面关注的人发布的商品动态列表
        $attentionUserList
            .removeDuplicates()
            // sink是一种订阅事件的方式
            .sink { userModels in
                Dlog(userModels.map { $0.id })
                // 获取关注的人的动态
                self.getAttentionUserMoments(userModels: userModels)
            }
            // 订阅事件后，还需要有个事件的回收，cancellable就是做这个事情的，类似于垃圾桶的机制
            .store(in: &cancellable)
        
        
        $myChannelList
            .removeDuplicates()
            .sink { myChannels in
                IdleFishUserDefaultsManager.shared.myChannels = myChannels
            }
            .store(in: &cancellable)
        
        // 我的频道变动通知，在这里请求服务器更新数据库
        $myChannelList
            .debounce(for: .seconds(1), scheduler: RunLoop.main)
            .removeDuplicates()
            .sink { myChannels in
                Dlog("我的频道个数发生变化，更新数据库记录")
                Dlog(myChannels)
                if myChannels.isEmpty {
                    return
                }
                Task {
                    await self.updateUserChannelList(userId: 1, channelIds: self.myChannelList.compactMap { $0.id })
                }
            }
            .store(in: &cancellable)
        
        // 选择的顶级分类发生变化，在这里请求服务器获取顶级分类下的子级分类列表
        $selectedSuperCategory
            .removeDuplicates()
            .sink { channel in
                
                Task {
                    await self.getChildGoodsCategoryList(superId: channel?.id ?? 1)
                }
            }
            .store(in: &cancellable)
        
        
//        $homeRecommendCurrTabIndex
//            .removeDuplicates()
//            .sink { index in
//                Dlog(index)
//            }
//            .store(in: &cancellable)
        
        getRecommendGoodsCardListWithSelectedCategoryPublisher
            .sink { isOk in
                
                // 排除myChannelList为空的情况
                if isOk == false {
                    return
                }
                
                guard let categoryId = self.myChannelList[self.homeRecommendCurrTabIndex].id else {
                    return
                }
                
                
                if self.channelGoodsCardList["\(categoryId)"]?.count ?? 0 > 0 {
                    Dlog("切换分类，无需请求")
                    return
                }
                
                Dlog("选择的分类id为：\(categoryId)")

                // 请求服务器
                Task {
                    
                    await self.getGoodsCardListWith(categoryId: categoryId, maxTime: nil)
                    
                }
                
            }
            .store(in: &cancellable)

    }
    
    func getGoodsCardListWith(categoryId CategoryId: Int, maxTime MaxTime: Int?) async {
        
        do {
            
            let maxTime = MaxTime ?? Date.currTime
            
            let result = try await NetworkTool.awaitRequest(request: API.user_channel_goods_list(category_id: CategoryId, max_time: maxTime), responseType: [GoodsCardModel].self)
            let goodsCardList = result.data ?? []
            
            if MaxTime == nil {
                self.channelGoodsCardList["\(CategoryId)"] = goodsCardList
            } else {
                self.channelGoodsCardList["\(CategoryId)"] = (self.channelGoodsCardList["\(CategoryId)"] ?? []) + goodsCardList
            }
        } catch {
            
            Dlog(error)
        }
    }
    
    
    /// 获取关注的人最近动态，本应该请求服务器获取，这里暂时从本地的数据组合进行模拟
    /// - Parameter userModels: 关注的人列表
    private func getAttentionUserMoments(userModels: [UserModel]) {
        
        var moments = [GoodsCardModel]()
        
        userModels.forEach { userModel in
            
            let randomForeachCount = Int.random(in: 1...10)
            
            (0..<randomForeachCount).forEach { _ in
                
                let moment = GoodsCardModel(goodsInfo: DEFAULT_GOODSINFO_MODELS[Int.random(in: 0..<9)], seller: userModel)
                moments.append(moment)
            }
        }
        
        attentionUserMoments = moments
    }
    
    
    /// 异步获取顶级商品分类
    func getSuperGoodsCategoryList() async {
        do {
            self.superCategoryList = try await fetchGoodsCategoryList(superId: 0)
            
            self.selectedSuperCategory = self.superCategoryList.first
        } catch {
            Dlog(error)
        }
    }
    
    
    /// 获取子级分类列表
    /// - Parameter superId: 父级分类id
    func getChildGoodsCategoryList(superId: Int) async {
        do {
            let childCategoryList = try await fetchGoodsCategoryList(superId: superId)
            
            self.selectedChildCategoryList = childCategoryList.filter { myChannelList.contains($0) == false }
            
        } catch {
            Dlog(error)
        }
    }
    
    
    /// 更新用户的频道列表
    /// - Parameters:
    ///   - userId: 用户id
    ///   - channelIds: 选择的频道id列表
    func updateUserChannelList(userId: Int, channelIds: [Int]) async {
        
        do {
            
            var channelStrIds: [String] = []
            for id in channelIds {
                if id == 0 {
                    continue
                } else {
                    channelStrIds.append(String(id))
                }
            }
           
            _ = try await updateUserChannelList(userId: userId, channel_ids: channelStrIds.joined(separator: ","))
        } catch {
            Dlog(error)
        }
    }
    
    func getCurrLocationCategoryList(cityName: String) async {
        
        do {
            self.currLocationCategoryList = try await fetchCurrLocationGoodsCategoryList(cityName: cityName)
            if self.currLocationCategoryList.count > 0 {
                Dlog("获取到当前城市下的商品分类")
            }
        } catch {
            Dlog(error)
        }
    }
}

